<?php
/**
 * 房源模型
 */

namespace app\crontab\model;

use app\common\lib\RespCode;
use app\common\model\BaseModel;
use custom\Curl;
use custom\HouseCount;
use custom\Log;
use custom\Mongo;
use custom\Redis;
use custom\TencentMap;
use map\BaiDu;
use think\Db;
use think\Exception;
use function Sodium\compare;

class House2 extends BaseModel {

    protected $table = 'house';

    protected $autoWriteTimestamp = true;
    protected $createTime = 'itime';
    protected $updateTime = 'utime';

    // 标题解析配置
    const AREA_CONFIGS = [
        // 京东
        1 => [
            '成都市' => [
                '双流区'         => ['天府新区'],
                '武侯区'         => ['天府新区'],
                '龙泉驿区'        => ['天府新区'],
                '成都高新技术产业开发区' => ['天府新区'],
            ],
            '西安市' => [
                '雁塔区' => ['高新区', '曲江新区'],
                '新城区' => ['高新区', '曲江新区'],
                '未央区' => ['高新区'],
            ],
            '重庆市' => [
                '綦江区' => ['万盛区']
            ],
            '绵阳市' => [
                '涪城区' => ['高新区']
            ],
        ],
        // 阿里
        2 => [
            '成都' => [
                '其它区' => ['天府新区', '高新区'],
                '双流区' => ['天府新区'],
            ],
            '西安' => [
                '其它区' => ['曲江新区', '高新区']
            ]
        ]
    ];

    //解析不到的区域并且置空的区
    const EMPTY_AREA = [
        '其它区'
    ];


    /**
     * 房源基本信息
     * @param $params
     * @return bool
     * @throws Exception
     */
    public function edit(&$params) {
        // 不存在就添加，存在不做变化
        if (!$old = $this->field('auction_id,id')->where(['sn' => $params['sn']])->find()) {
            // 新增房源
            if (!$id = $this->customName('erp_house')->customInsert($params)) {
                throw new Exception('新增房源失败', RespCode::PARAMS_ERR);
            }
            $params['house_id'] = $id;
            return true;
        }

        $params['house_id'] = $old->id;
        return true;
    }

    /**
     * 房源绑定小区
     * @param $params
     * @return bool
     * @throws Exception
     * @throws \think\exception\PDOException
     */
    public function bindVillage($params) {
        // 获取商圈id
        if (!$village = db('house_village')->where(['ajk_id' => $params['village_id']])->field('business_area,id')->find()) {
            throw new Exception('不存在该小区', RespCode::PARAMS_ERR);
        }
        // 获取商圈信息
        if (!$baData = db('business_area')->field('city_id,city_ids')->where(['id' => $village['business_area']])->find()) {
            throw new Exception('不存在该商圈', RespCode::PARAMS_ERR);
        }

        // 获取房源id
        $where = ['source_id' => $params['house_id']];
        switch ($params['source_id']) {
            case 1:
                $id = db('house_jd')->where($where)->value('house_id');
                break;
            case 2:
                $id = db('house_ali')->where($where)->value('house_id');
                break;
            default:
                $id = 0;
                break;
        }

        if (!$id) {
            throw new Exception('房源拍卖信息不存在', RespCode::PARAMS_ERR);
        }

        $params['village_id'] = $village['id'];
        // 更新绑定信息
        $uData = [
            'city_code'        => $baData['city_code'],
            'city_codes'       => $baData['city_codes'],
            'business_area_id' => $village['business_area'],
            'village_id'       => $params['village_id'],
        ];
        if (!$this->where(['id' => $id])->update($uData)) {
            throw new Exception('房源绑定小区失败', RespCode::PARAMS_ERR);
        }
        return true;
    }

    /**
     * 验证参数
     * @param $params
     * @param $fields
     * @throws Exception
     */
    public static function checkParams(&$params, $fields) {
        foreach ($fields as $key => $field) {
            if (!isset($params[$field]) || (empty($params[$field]) && $params[$field] !== 0))
                throw new Exception("{$field} 不能为空", RespCode::PARAMS_ERR);
        }
    }

    /**
     * 新增拍卖&房源数据
     * @param $data
     * @throws Exception
     * @throws \think\exception\PDOException
     */
    public static function addNewData($data, $sourceType) {
        list($houseData, $houseAuctionData) = self::handleData($data, 2, $sourceType);
//        print_r($houseData);
//        echo "--------------------------------\n";
//        print_r($houseAuctionData);
//        die;
        if (!$auction_id = db("house_auction")->strict(false)->insertGetId($houseAuctionData))
            throw new Exception("新增拍卖&房源数据 - 新增house_auction错误", RespCode::PARAMS_ERR);
        $houseData['auction_id'] = $auction_id;
        if (!$house_id = db("house")->strict(false)->insertGetId($houseData))
            throw new Exception("新增拍卖&房源数据 - 新增house错误", RespCode::PARAMS_ERR);
        $res = db("house_auction")->where('id', $auction_id)->strict(false)->update(['house_id' => $house_id]);
        if ($res === false)
            throw new Exception("新增拍卖&房源数据 - 更新house_auction错误", RespCode::PARAMS_ERR);
    }

    /**
     *  同步拍卖、房源数据
     * _id、house_id、title、start_time、initial_price、deal_time、final_price、auction_status、type、enroll_num、remind_num
     * @param $params
     * @param $has_house_auction
     * @param $house_data
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public static function handleSyncData($params, $has_house_auction, $house_data) {
        $syncData = $params;
        //删除不需要的字段
        if (isset($syncData['_id'])) unset($syncData['_id']);
        if (isset($syncData['title'])) unset($syncData['title']);
        if (isset($syncData['house_id'])) unset($syncData['house_id']);
        if (isset($syncData['itime'])) unset($syncData['itime']);
        if (isset($syncData['id'])) unset($syncData['id']);
        //统一转换金额
        $syncData = price_arr_deal($syncData, 1);
        //绑定房源
        $syncData['house_id'] = $house_data['id'];
        $syncData['source_id'] = $params['house_id'];
        $syncData['soure_updatetime'] = time();

        $syncData['type'] == 4 ? $syncData['pay_selloff'] = $syncData['initial_price'] : $syncData['pay_selloff'] = 0;
//        print_r($syncData);die;

        //重新计算折扣
        $syncData['discount'] = self::calculation_discount($syncData['initial_price'], $house_data['market_price']);
//        print_r($syncData);
//        die;

        //更新拍卖信息，所有字段更新
        if (db("house_auction")->where("source_id", $params['house_id'])->strict(false)->update($syncData) === false)
            throw new Exception("更新house_auction错误", RespCode::PARAMS_ERR);

        $houseUpdate = [];
        if (isset($syncData['source_url'])) $houseUpdate['source_url'] = $syncData['source_url'];

        if (!empty($houseUpdate)) {
            if (db("house")->where("title", $params['title'])->strict(false)->update($houseUpdate) === false)
                throw new Exception("更新house错误", RespCode::PARAMS_ERR);
        }
    }

    /**
     * 已存在房源绑定新的拍卖信息
     * @param $data
     * @param $has_house
     * @param $sourceType
     * @throws Exception
     * @throws \think\exception\PDOException
     */
    public static function bindNewAuction($data, $has_house, $sourceType) {
        list($houseData, $houseAuctionData) = self::handleData($data, 1, $sourceType);
        $houseAuctionData['market_price'] = $has_house['market_price'];

        //计算折扣
        $houseAuctionData['discount'] = self::calculation_discount($houseAuctionData['initial_price'], $houseAuctionData['market_price']);

        //绑定到房源
        $houseAuctionData['house_id'] = $has_house['id'];
        if (!$auction_id = db("house_auction")->strict(false)->insertGetId($houseAuctionData))
            throw new Exception("已存在房源绑定新的拍卖信息 - 新增house_auction错误", RespCode::PARAMS_ERR);

        //更新房源对应的拍卖id
        $houseUpdate['auction_id'] = $auction_id;

        //更新房源source_url
        if (isset($houseAuctionData['source_url'])) $houseUpdate['source_url'] = $houseAuctionData['source_url'];

        if (db("house")->where('id', $has_house['id'])->strict(false)->update($houseUpdate) === false)
            throw new Exception("已存在房源绑定新的拍卖信息 - 更新house错误", RespCode::PARAMS_ERR);
    }

    /**
     * @type=1 新增拍卖
     * @type=2 全部新增
     * 房源、拍卖数据处理
     * @param $params
     * @param $type
     * @param $sourceType
     * @return array
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function handleData($params, $type, $sourceType) {
        $params = price_arr_deal($params, 1);//金额转换
        $houseData = [];
        if ($type == 1) goto Auction;

        //获取省市区及
        list($region, $pCodes) = self::city($params, $sourceType);

        $vinfo['price'] = 0;
        $vinfo['village_id'] = 0;
        //获取小区id和小区均价
        if ($params['address']) $vinfo = HouseCount::getVillageInfo((string)$params['_id'], $region['name2'], $params['address']);

        //计算市场价
        $market_price = $params['market_price'] ?? self::calculation_market_price($params['build_area'] ?? 0, $vinfo['price']);

        //房源数据处理
        $houseData['village_id'] = $vinfo['village_id'];
        $houseData['business_area_id'] = 0;
        $houseData['auction_id'] = 0;
        $houseData['source_type'] = $sourceType;
        $houseData['source_url'] = $params['source_url'] ?? '';
        $houseData['anjuke_url'] = '';
        $houseData['title'] = $params['title'];
        $houseData['sn'] = md5($params['title']);
        $houseData['cover'] = $params['cover'] ?? "";
        $houseData['province'] = $region['name1'] ?? '';
        $houseData['city'] = $region['name2'] ?? '';
        $houseData['area'] = $region['name3'] ?? "";
        $houseData['city_code'] = $region['city_code3'] ?? $region['city_code2'];
        $houseData['city_codes'] = $pCodes;
        $houseData['address'] = $params['address'] ?? "";
        $houseData['map_address'] = '';
        $houseData['district'] = $params['district'] ?? "";
        $houseData['floor'] = $params['floor'] ?? 0;
        $houseData['max_floor'] = $params['max_floor'] ?? 0;
        $houseData['bedroom'] = $params['bedroom'] ?? 0;
        $houseData['livingroom'] = $params['livingroom'] ?? 0;
        $houseData['build_time'] = $params['build_time'] ?? 0;
        $houseData['build_area'] = isset($params['build_area']) ? $params['build_area'] * 10000 : 0;
        $houseData['renovation_type'] = $params['renovation_type'] ?? 0;
        $houseData['house_type_id'] = 1;
        $houseData['house_type_ids'] = '';
        $houseData['house_cate'] = 0;
        $houseData['living_type'] = $params['living_type'] ?? 1;
        $houseData['lease_remark'] = $params['lease_remark'] ?? '';
        $houseData['property_type'] = $params['property_type'] ?? 1;
        $houseData['warrant'] = $params['warrant'] ?? '';
        $houseData['anjuke_price'] = 0;
        $houseData['itime'] = time();
        $houseData['utime'] = 0;
        $houseData['source_utime'] = time();
        $houseData['staff_id'] = 0;
        $houseData['important'] = 0;
        $houseData['is_shelf'] = 0;
        $houseData['is_update'] = 0;
        $houseData['is_complete'] = 0;
        $houseData['customer_count'] = 0;
        $houseData['pic'] = $params['pics'] ?? '';
        $houseData['lng'] = 0;
        $houseData['lat'] = 0;
        $houseData['location'] = Db::raw("POINT(0, 0)");
        $houseData['from'] = 1;
        $houseData['bulu_time'] = 0;
        $houseData['market_price'] = $market_price;
        $houseData['source_province'] = $params['province'] ?? '';
        $houseData['source_city'] = $params['city'] ?? '';
        $houseData['source_area'] = $params['area'] ?? '';

        //拍卖数据处理
        Auction:
        if ($type == 1) $market_price = 0;

        $houseAuctionData['house_id'] = 0;
        $houseAuctionData['source_id'] = $params['house_id'];
        $houseAuctionData['source_type'] = $sourceType;
        $houseAuctionData['court_name'] = $params['court_name'] ?? "";
        $houseAuctionData['start_time'] = $params['start_time'] ?? 0;
        $houseAuctionData['end_time'] = $params['end_time'] ?? 0;
        $houseAuctionData['institution'] = $params['contact_name'] ?? "";
        $houseAuctionData['contact_name'] = $params['contact_name'] ?? "";
        $houseAuctionData['contact_tel'] = $params['contact_tel'] ?? "";
        $houseAuctionData['initial_price'] = $params['initial_price'] ?? 0;
        $houseAuctionData['bond'] = $params['bond'] ?? 0;
        $houseAuctionData['consult_price'] = $params['consult_price'] ?? 0;
        $houseAuctionData['market_price'] = $market_price;
        $houseAuctionData['discount'] = self::calculation_discount($houseAuctionData['initial_price'], $houseAuctionData['market_price']);
        $houseAuctionData['type'] = in_array(isset($params['type']) ?? 0, [1, 2, 3, 4, 5, 6]) ? $params['type'] : 0;
        $houseAuctionData['pay_selloff'] = $houseAuctionData['type'] == 4 ? $houseAuctionData['initial_price'] : 0;
        $houseAuctionData['predict_price'] = 0;
        $houseAuctionData['price_lower_offset'] = $params['price_lower_offset'] ?? 0;
        $houseAuctionData['final_price'] = $params['final_price'] ?? 0;
        $houseAuctionData['tail_money_date'] = 0;
        $houseAuctionData['enroll_num'] = $params['enroll_num'] ?? 0;
        $houseAuctionData['access_num'] = $params['access_num'] ?? 0;
        $houseAuctionData['remind_num'] = $params['remind_num'] ?? 0;
        $houseAuctionData['itime'] = time();
        $houseAuctionData['day_itime'] = strtotime(date("Y-m-d"));
        $houseAuctionData['month_itime'] = strtotime(date("Y-m"));
        $houseAuctionData['utime'] = 0;
        $houseAuctionData['soure_updatetime'] = time();
        $houseAuctionData['deal_time'] = $params['deal_time'] ?? 0;
        $houseAuctionData['bid_count'] = $params['bid_count'] ?? 0;
        $houseAuctionData['auction_status'] = $params['auction_status'] ?? 0;
        $houseAuctionData['source_url'] = $params['source_url'] ?? "";
        return [
            $houseData,
            $houseAuctionData
        ];
    }

    /**
     * 获取地理信息
     * @param $address
     * @param $lng
     * @param $lat
     * @param $city
     * @return array
     * @throws Exception
     */
    public static function getAddressInfoByMaps($address, $city) {
        //通过地址解析经纬度
        $res1 = BaiDu::placeSearch($address, $city, '住宅');
        $lat = $res1['results'][0]['location']['lat'] ?? 0;
        $lng = $res1['results'][0]['location']['lng'] ?? 0;
        if (!empty($lat) && !empty($lng)) {
            $res2 = BaiDu::getByLocation($lat, $lng);
            if (!empty($res2['result'])) {
                $lng = round($res2['result']['location']['lng'] ?? $lng, 6);
                $lat = round($res2['result']['location']['lat'] ?? $lat, 6);
                $data = [
                    'province'    => $res2['result']['addressComponent']['province'] ?? '',
                    'city'        => $res2['result']['addressComponent']['city'] ?? '',
                    'area'        => $res2['result']['addressComponent']['district'] ?? '',
                    'district'    => $res2['result']['addressComponent']['street'] ?? '',
                    'map_address' => $res2['result']['formatted_address'],
                    'city_code'   => $res2['result']['addressComponent']['adcode'] ?? 0,
                    'lng'         => $lng,
                    'lat'         => $lat,
                ];
            }
        } else {
            $data = [
                'province'    => '',
                'city'        => '',
                'area'        => '',
                'district'    => '',
                'map_address' => '',
                'city_code'   => 0,
                'lng'         => 0,
                'lat'         => 0,
            ];
        }
        return $data;
    }

    /**
     * 城市解析
     * @param $data
     * @return bool
     */
    protected static function city($params, $sourceType) {
        switch ($sourceType) {
            case 1:
                $field = 'new_name_jd';
                break;
            case 2:
                $field = 'new_name_ali';
                break;
        }
        // 获取城市对应的id
        $city_relation1 = db('city_relation')
            ->where($field, $params['city'])
            ->value('id');
        if (empty($city_relation1)) throw new Exception($params['city'] . '|' . '$city_relation1为空', RespCode::PARAMS_ERR);
        // 获取城市下面的区域分级
        $pids = db('city_relation')
            ->where('pid', $city_relation1)
            ->column('id');
        if (empty($pids)) throw new Exception($city_relation1 . '|' . '$pids为空', RespCode::PARAMS_ERR);
        // 是否需要解析标题
        $_area = self::isTitle($sourceType, $params['city'], $params['area'], $params['title']);
        //去找城市city_code
        if (empty($_area)) {
            $cityCode = db('city_relation')
                ->where($field, $params['city'])
                ->value('city_code');
            if (empty($cityCode)) throw new Exception($params['city'] . '|' . '$cityCode为空', RespCode::PARAMS_ERR);
            $region = db('region')
                ->alias('r1')
                ->join('region r2', 'r1.id=r2.pid')
                ->where('r2.city_code', $cityCode)
                ->field('r1.name as name1,r2.name as name2,r1.city_code as city_code1,r2.city_code as city_code2')
                ->find();
            if (empty($region)) throw new Exception(json_encode($cityCode) . '|' . "region1为空", RespCode::PARAMS_ERR);
            $pCodes = ",{$region['city_code1']},{$region['city_code2']}, ";
        } else {
            // 去找区域city_code
            $areaCode = db('city_relation')
                ->where('pid', 'in', $pids)
                ->where($field, $_area)
                ->value('city_code');
            if (empty($areaCode)) throw new Exception($_area . '|' . json_encode($pids) . '|' . '$areaCode为空', RespCode::PARAMS_ERR);
            //通过区域code去找region
            $region = db('region')
                ->alias('r1')
                ->join('region r2', 'r1.id=r2.pid')
                ->join('region r3', 'r2.id=r3.pid')
                ->where('r3.city_code', $areaCode)
                ->field('r1.name as name1,r2.name as name2,r3.name as name3,r1.city_code as city_code1,r2.city_code as city_code2,r3.city_code as city_code3')
                ->find();
            if (empty($region)) throw new Exception(json_encode($areaCode) . '|' . "region2为空", RespCode::PARAMS_ERR);
            $pCodes = ",{$region['city_code1']},{$region['city_code2']},{$region['city_code3']}, ";
        }
        return [
            $region,
            $pCodes
        ];
    }

    /**
     * 解析标题
     * @param $source_type
     * @param $city
     * @param $area
     * @param $title
     * @return mixed
     */
    protected static function isTitle($source_type, $city, $area, $title) {
        $cityConfig = self::AREA_CONFIGS;
        if (isset($cityConfig[$source_type][$city]) && !empty($cityConfig[$source_type][$city][$area])) {
            foreach ($cityConfig[$source_type][$city][$area] as $value) {
                if (strpos($title, $value) !== false) {
                    return $value;
                }
            }
        }
        if (in_array($area, self::EMPTY_AREA)) {
            return '';
        }
        return $area;
    }

    /**
     * 计算市场价
     * @param $build_area
     * @param $price
     */
    public static function calculation_market_price($build_area, $price) {
        if ($build_area > 0 && $price > 0) {
            //房源面积 x 小区均价
            $market_price = moneyFormat($build_area * $price, 1);
        } else {
            $market_price = 0;
        }
        return $market_price;
    }

    /**
     * 计算折扣
     * @param $initial_price
     * @param $market_price
     * @return float|int
     */
    public static function calculation_discount($initial_price, $market_price) {
        $discount = -1;
        if (!empty($market_price)) {
            // 当初始价 小于等于市场价时，才计算折扣
            if ($initial_price < $market_price) {
                $discount = round($initial_price / $market_price * 10, 2);
                $discount < 1 && $discount = 0;
                $discount >= 10 && $discount = 10;
            }
        }
        return $discount;
    }

    /**
     * 数据处理
     * @param $v1
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public static function dealData($v1, $sourceType) {
        $house_auction = db("house_auction")->where("source_id", $v1['house_id'])->find();
        $house = db("house")->where('sn', md5($v1['title']))->find();
        Db::startTrans();
        //更新拍卖、房源
        if ($house_auction && $house) {
//            echo 1;
//            die;
            self::handleSyncData($v1, $house_auction, $house);
        } //已存在房源绑定新的拍卖信息
        elseif (empty($house_auction) && $house) {
//            echo 2;
//            die;
            self::bindNewAuction($v1, $house, $sourceType);
        } //新增拍卖&房源数据
        else {
//            echo 3;
//            die;
            self::addNewData($v1, $sourceType);
        }
        //处理完毕
        Db::commit();
    }

    /**
     * 逐条处理
     * @param $data
     * @param $page
     * @param $redisKey
     * @param $errNum
     */
    public static function doOne($data, $redisKey, $errNum, $sourceType) {
        $redisModel = Redis::getInstance();
        foreach ($data as $k1 => $v1) {
            try {
                $v1 = (array)$v1;
                if (isset($v1['time_arr'])) unset($v1['time_arr']);
                //验证参数
                self::checkParams($v1, ['house_id', 'title', '_id']);
                //删除为空的字段
                foreach ($v1 as $k2 => $v2) if (trim($v2) === '') unset($v1[$k2]);
                //数据处理
                self::dealData($v1, $sourceType);
                // 记录这页最后一条的utime
                if (!isset($data[$k1 + 1])) $redisModel->set($redisKey, $v1['utime']);
            } catch (Exception $e) {
                Db::rollback();
                $err = "ID->{$v1['_id']} | 异常信息:{$e->getMessage()} | 异常所在的代码行:{$e->getLine()} | 异常文件{$e->getFile()}" . "\r\n\r\n";
                if ($errNum >= 3) break;
                $errNum++;
                Log::write($err, "{$redisKey}_Err.log");
                continue;
            }
        }//endforeach
    }

}
